package com.jcooky.tutorfs.proxy;

import java.nio.ByteOrder;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jcooky.tutorfs.proxy.filesystem.AbstractFileSystem;
import com.jcooky.tutorfs.proxy.processor.MessageProcessor;
import com.jcooky.tutorfs.proxy.processor.ProcessException;
import com.jcooky.tutorfs.proxy.processor.factory.AbstractProcessorFactory;
import com.jcooky.tutorfs.proxy.protocol.AbstractMessage;

public class TutorFsProxyHandler extends IoHandlerAdapter {
	private static final Logger logger = LoggerFactory
			.getLogger(TutorFsProxyHandler.class);

	private AbstractFileSystem fs;

	public TutorFsProxyHandler(AbstractFileSystem fs) {
		this.fs = fs;
	}

	public void sessionOpened(IoSession session) throws Exception {
		session.setAttribute(Attributes.BUFFER, IoBuffer.allocate(1024, true)
				.setAutoExpand(true).clear());
		session.setAttribute(Attributes.FILE_SYSTEM, fs);
	}

	public void messageReceived(IoSession session, Object message)
			throws Exception {
		IoBuffer sessionBuffer = (IoBuffer) session
				.getAttribute(Attributes.BUFFER);
		logger.debug("messageBuffer hexdump : {}", (IoBuffer) message);
		sessionBuffer.put((IoBuffer) message);
		sessionBuffer.flip();

		process(session, sessionBuffer);
	}

	public void exceptionCaught(IoSession session, Throwable cause)
			throws Exception {
		logger.error(cause.getMessage(), cause);
	}

	private void process(IoSession session, IoBuffer buf)
			throws ProcessException {
		logger.debug("sessionBuffer hexdump : {}", buf.getHexDump());
		byte type = buf.get();
		logger.debug("message type : {}", type);
		AbstractMessage msg = AbstractMessage.getMessage(type);
		if (buf.remaining() < msg.length()) {
			logger.debug("remaining less than msg.length()");
			buf.position(buf.position() + buf.remaining());
		} else {
			msg.fromBytes(buf);
			buf.compact();

			process(session, type, msg);
		}
	}

	private void process(IoSession session, int type, AbstractMessage msg)
			throws ProcessException {
		AbstractProcessorFactory processorFactory = AbstractProcessorFactory
				.getFactory();
		MessageProcessor<AbstractMessage> processor = processorFactory
				.getProcessor(type);
		processor.process(session, msg);
	}
}
